﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Data.OleDb;
//using System.Data.SqlClient;
using JSClass;
using MapTools;
using System.Xml;
using System.Net;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace MakeShapeFile
{
    public partial class Form1 : Form
    {
        private Thread th;              // 쓰레드 생성
        private const int WM_VSCROLL = 0x115;
        private const int SB_BOTTOM = 7;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr IParam);

        private string output = "";
        private string layerName = "";
        private string layerKName = "";
        public Form1()
        {
            InitializeComponent();
        }

        private void btnKlis_Click(object sender, EventArgs e)
        {
            try
            {
                th = new Thread(new ThreadStart(this.StartProcess));      // 쓰레드 클래스의 새 인스턴스를 초기화
                CheckForIllegalCrossThreadCalls = false;        // 크로스 스레드 체크 안함.
                th.Start();                                     // 쓰레드 실행
            }
            catch { }
        }

        private void btnGetall_Click(object sender, EventArgs e)
        {
            try
            {
                th = new Thread(new ThreadStart(this.GetAllData));      // 쓰레드 클래스의 새 인스턴스를 초기화
                CheckForIllegalCrossThreadCalls = false;        // 크로스 스레드 체크 안함.
                th.Start();                                     // 쓰레드 실행
            }
            catch { }
        }


        private void GetAllData()
        {
            for (int idx = 0; idx < comLayer.Items.Count; idx++)
            {
                comLayer.SelectedIndex = idx;
                StartProcess();
            }
        }

        private void StartProcess()
        {
            int hjgyIdx = 2;
            layerName = "SID";
            layerKName = comLayer.Text;
            if (layerKName.Equals(""))
            {
                MessageBox.Show("생성할 레이어를 선택하세요.");
                return;
            }
            if (layerKName.Equals("시군구경계")) layerName = "SGG";
            if (layerKName.Equals("읍면동경계")) layerName = "EMD";
            if (layerKName.Equals("리경계")) layerName = "RI";
            if (layerKName.Equals("시군구경계")) hjgyIdx = 5;
            if (layerKName.Equals("읍면동경계")) hjgyIdx = 8;
            if (layerKName.Equals("리경계")) hjgyIdx = 10;

            output = @"D:\ArcBruTile\shape\LEPS_" + layerName;
            
            Log("-------------------------------------------------");
            Log("행정경계 shape 생성을 시작합니다.");
            Log("");

            ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Polygon;
            Log(layerKName + " shape(.shp)파일 생성");
            IntPtr hShp = ShapeLib.SHPCreate(output, shpType);
            Log(layerKName + " dBase(.dbf)파일 생성");
            IntPtr hDbf = ShapeLib.DBFCreate(output);
            
            ShapeLib.DBFAddField(hDbf, layerName + "_CD", ShapeLib.DBFFieldType.FTString, 10, 0);
            ShapeLib.DBFAddField(hDbf, layerName + "_NM", ShapeLib.DBFFieldType.FTString, 30, 0);
            
            // free resources
            ShapeLib.SHPClose(hShp);
            
            ShapeLib.DBFClose(hDbf);
            
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT HJGYCODE, trim(sdmyeong||' '||sggmyeong||' '||emdmyeong||' '||rmyeong) ADDRESSNAME ")
                .Append("FROM code_hjgy A  ")
                .Append("WHERE SYYEOBU='1' ");

            if (layerKName.Equals("시도경계")) sb.Append("AND SUBSTR(HJGYCODE,3,8) = '00000000' ");
            if (layerKName.Equals("시군구경계")) sb.Append("AND SUBSTR(HJGYCODE,3,3) <> '000' AND SUBSTR(HJGYCODE,6,5) = '00000' ");
            if (layerKName.Equals("읍면동경계")) sb.Append("AND SUBSTR(HJGYCODE,6,3) <> '000' AND SUBSTR(HJGYCODE,9,2) = '00' ");
            if (layerKName.Equals("리경계")) sb.Append("AND SUBSTR(HJGYCODE,9,2) <> '00' ");

            TableQuery myQuery = new TableQuery(sb.ToString());
            int rowCnt = myQuery.getRowCount();

            Log(rowCnt + "개의 코드 추출");
            
            for (int nRow = 0; nRow < rowCnt; nRow++)
            {
                string hjgycode = myQuery.getValueAt(nRow, 0).ToString();
                string addressname = myQuery.getValueAt(nRow, 1).ToString();
                hjgycode = hjgycode.Substring(0, hjgyIdx);
                ReadKLISData(hjgycode, addressname);

                int percent = ((nRow + 1) * 100) / rowCnt;
                this.pgsbar1.Value = percent;

                lblCount.Text = percent + "% 완료 [" + (nRow + 1) + "/" + rowCnt + "]";
            }
            Log(layerKName + " shape 생성완료");
            Log("");
            
            this.pgsbar1.Value = 0;
        }
        private void ReadKLISData(string hjgycode, string addressname)
        {
            ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Polygon;

            IntPtr hShp = ShapeLib.SHPOpen(output, "rb+");
            IntPtr hDbf = ShapeLib.DBFOpen(output, "rb+");
            int shpCnt = ShapeLib.DBFGetRecordCount(hDbf);

            string theUrl = "http://61.108.157.29:8880/gnis/wfs?";
            theUrl += "GDX=UMD_GEN_WFS.xml&SERVICE=WFS&VERSION=1.1.0";
            theUrl += "&REQUEST=GetFeature&TYPENAME=LEPS_" + layerName + "&SRSNAME=EPSG:4326";
            theUrl += "&FILTER=";
            theUrl += "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\">";
            theUrl += "<ogc:PropertyIsEqualTo matchCase=\"true\">";
            theUrl += "<ogc:PropertyName>" + layerName + "_CD</ogc:PropertyName>";
            theUrl += "<ogc:Literal>" + hjgycode + "</ogc:Literal>";
            theUrl += "</ogc:PropertyIsEqualTo>";
            theUrl += "</ogc:Filter>";

            try
            {
                // Create the XmlDocument.
                XmlDocument doc = new XmlDocument();
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(theUrl);
                req.Credentials = CredentialCache.DefaultCredentials;
                // Get the response.
                using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
                {
                    StreamReader sr = new StreamReader(res.GetResponseStream());
                    try
                    {
                        doc.LoadXml(sr.ReadToEnd());
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Url return failed: " + ex.Message);
                        return;
                    }

                    XmlNodeList posListArray = doc.GetElementsByTagName("gml:posList");
                    if (posListArray.Count > 0)
                    {
                        bool isContinue = true;
                        string hjgy_cd = doc.GetElementsByTagName("sf:" + layerName + "_CD").Item(0).InnerText;
                        string hjgy_nm = doc.GetElementsByTagName("sf:" + layerName + "_NM").Item(0).InnerText;

                        if (isContinue)
                        {
                            for (int row = 0; row < posListArray.Count; row++)
                            {
                                XmlNode posList = posListArray.Item(row);
                                string posListStr = MakePoslist2STGeometry(posList.InnerText);

                                string[] ptArray = posListStr.Split(',');
                                int ptCnt = ptArray.Length;
                                int ptIdx = 0;

                                double[] xCoord = new double[ptCnt];
                                double[] yCoord = new double[ptCnt];

                                foreach (string ptStr in ptArray)
                                {
                                    string xCoordStr = ptStr.Split(' ')[0];
                                    string yCoordStr = ptStr.Split(' ')[1];

                                    xCoord[ptIdx] = Double.Parse(xCoordStr);
                                    yCoord[ptIdx] = Double.Parse(yCoordStr);
                                    ptIdx++;
                                }

                                //IntPtr pShp22 = ShapeLib.SHPCreateObject(shpType, -1, 0, null, null, 1, xCoord, yCoord, null, null);
                                IntPtr pShp = ShapeLib.SHPCreateSimpleObject(shpType, ptCnt - 1, xCoord, yCoord, null);
                                ShapeLib.SHPWriteObject(hShp, -1, pShp);
                                ShapeLib.SHPDestroyObject(pShp);
                                ShapeLib.DBFWriteStringAttribute(hDbf, shpCnt, 0, hjgy_cd);
                                ShapeLib.DBFWriteStringAttribute(hDbf, shpCnt, 1, hjgy_nm);

                                shpCnt++;
                            }
                        }
                    }
                    else
                    {
                        Log(layerKName + " 자료 누락 : " + addressname + "[" + hjgycode + "]");
                    }
                }
            }
            catch (Exception ee)
            {
                Log(layerKName + " 자료 누락 : " + addressname + "[" + hjgycode + "]");
                Log("검색 오류 : " + ee.Message);
            }
            
            // free resources
            ShapeLib.SHPClose(hShp);
            ShapeLib.DBFClose(hDbf);
        }
        private string MakePoslist2STGeometry(string restr)
        {
            string returnStr = "";
            var seper = true;
            string[] restrArray = restr.Split(' ');
            foreach (string point in restrArray)
            {
                if (seper)
                {
                    returnStr += point + " ";
                    seper = false;
                }
                else
                {
                    returnStr += point + ",";
                    seper = true;
                }
            }
            returnStr = returnStr.Substring(0, returnStr.Length - 1);
            return returnStr;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            WriteShapeFile();
        }
        private void WriteShapeFile()
        {
            string xField = "PTX";
            string yField = "PTY";

            string strConnect = "Provider=OraOLEDB.Oracle.1;Password=exgis2011;Persist Security Info=True;User ID=exgis2011;Data Source=oragis";
            string table = "SHAPELIB";
            if (output.ToUpper().EndsWith(".SHP"))
                output = output.Substring(0, output.Length - 4);

            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT * FROM ")
                .Append(table)
                .Append(" WHERE ")
                .Append(xField)
                .Append(" IS NOT NULL AND ")
                .Append(yField)
                .Append(" IS NOT NULL");

            OleDbConnection cn = new OleDbConnection(strConnect);
            OleDbCommand cm = new OleDbCommand(sb.ToString(), cn);
            // Open Connection
            try
            {
                cn.Open();
            }
            catch (OleDbException ex)
            {
                MessageBox.Show("Connection failed: " + ex.Message);
                MessageBox.Show("\\nnPress any key to exit");
                return;
            }
            // Execute command
            OleDbDataReader dr = cm.ExecuteReader();

            ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Point;

            // create shapefile
            IntPtr hShp = ShapeLib.SHPCreate(output, shpType);
            if (hShp.Equals(IntPtr.Zero))
            {
                MessageBox.Show("\nCould not create {0}.shp\nProbable cause: File is in use by EasyStreets\n\nPress any key to exit", output);
                Console.ReadLine();
                return;
            }

            int iShape = 0;
            double[] xCoord = new double[1];
            double[] yCoord = new double[1];
            bool flag = true;

            IntPtr hDbf = IntPtr.Zero;
            DataTable dt = new DataTable();
            System.Collections.Hashtable ht = new System.Collections.Hashtable();
            while (dr.Read())
            {
                if (flag)
                {
                    flag = false;
                    // create dbase file
                    hDbf = ShapeLib.DBFCreate(output);
                    if (!hDbf.Equals(IntPtr.Zero))
                    {
                        dt = dr.GetSchemaTable();
                        dt.Columns.Add("dBaseName");
                    }
                    int ordinal = 0;
                    foreach (DataRow row in dt.Rows)
                    {
                        string name = row["ColumnName"].ToString().ToUpper();
                        if (name.Length > 10)
                            name = name.Substring(0, 10);
                        int i = 0;
                        while (ht.ContainsKey(name))
                        {
                            string iVal = (i++).ToString();
                            if (name.Length + iVal.Length > 10)
                                name = name.Substring(0, 10 - iVal.Length) + iVal;
                            else
                                name = name + iVal;
                        }
                        ht.Add(name, ordinal++);
                        row["dBaseName"] = name;
                        string type = row["DataType"].ToString();
                        switch (type)
                        {
                            case "System.Int32":
                            case "System.Int16":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTInteger, 16, 0);
                                break;
                            case "System.String":
                                int len = Math.Min(255, int.Parse(row["ColumnSize"].ToString()));
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTString, len, 0);
                                break;
                            case "System.Boolean":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTLogical, 5, 0);
                                break;
                            case "System.Double":
                            case "System.Float":
                                int prec = int.Parse(row["NumericPrecision"].ToString());
                                int scale = int.Parse(row["NumericScale"].ToString());
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTDouble, prec, scale);
                                break;
                            case "System.DateTime":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTInteger, 8, 0);
                                break;
                            default:
                                ht.Remove(name);
                                row["dBaseName"] = null;
                                ordinal--;
                                break;
                        }
                    }
                }

                if (dr[xField] is DBNull || dr[yField] is DBNull)
                    continue;

                xCoord[0] = Double.Parse(dr[xField].ToString());
                yCoord[0] = Double.Parse(dr[yField].ToString());

                IntPtr pShp = ShapeLib.SHPCreateObject(shpType, -1, 0, null, null, 1, xCoord, yCoord, null, null);
                ShapeLib.SHPWriteObject(hShp, -1, pShp);
                ShapeLib.SHPDestroyObject(pShp);

                foreach (DataRow row in dt.Rows)
                {
                    if (row["dBaseName"] == null)
                        continue;
                    if (row["dBaseName"] == DBNull.Value)
                        continue;

                    string fieldName = row["ColumnName"].ToString();
                    if (dr[fieldName] is DBNull)
                        continue;
                    //int ordinal = (int)ht[row["dBaseName"].ToString()];
                    int ordinal = (int)ht[fieldName];

                    switch (row["DataType"].ToString())
                    {
                        case "System.Int32":
                        case "System.Int16":
                            ShapeLib.DBFWriteIntegerAttribute(hDbf, iShape, ordinal, int.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.String":
                            ShapeLib.DBFWriteStringAttribute(hDbf, iShape, ordinal, dr[fieldName].ToString());
                            break;
                        case "System.Boolean":
                            ShapeLib.DBFWriteLogicalAttribute(hDbf, iShape, ordinal, bool.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.Double":
                        case "System.Float":
                            ShapeLib.DBFWriteDoubleAttribute(hDbf, iShape, ordinal, double.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.DateTime":
                            DateTime date = DateTime.Parse(dr[fieldName].ToString());
                            ShapeLib.DBFWriteDateAttribute(hDbf, iShape, ordinal, date);
                            break;
                    }
                }
                iShape++;
            }
            // free resources
            ShapeLib.SHPClose(hShp);
            ShapeLib.DBFClose(hDbf);
            cn.Close();

            MessageBox.Show("\nCreated shapefile with " + iShape.ToString() + " workorders");
            //System.Threading.Thread.Sleep(3000);
            Application.Exit();
        }

        private void MakeNewShapeFile()
        {
            string xField = "PTX";
            string yField = "PTY";

            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT * FROM ")
                .Append("SHAPELIB")
                .Append(" WHERE ")
                .Append(xField)
                .Append(" IS NOT NULL AND ")
                .Append(yField)
                .Append(" IS NOT NULL");

            ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Point;
            //ShapeLib.ShapeType shpType2 = ShapeLib.ShapeType.PolygonM;

            IntPtr hShp = ShapeLib.SHPCreate(output, shpType);
            if (hShp.Equals(IntPtr.Zero))
            {
                MessageBox.Show("\nCould not create {0}.shp\nProbable cause: File is in use by EasyStreets\n\nPress any key to exit", output);
                return;
            }
            int iShape = 0;
            double[] xCoord = new double[1];
            double[] yCoord = new double[1];

            bool flag = true;

            IntPtr hDbf = IntPtr.Zero;

            //DataTable dt = new DataTable();
            TableQuery myQuery = new TableQuery(sb.ToString());
            int rowCnt = myQuery.getRowCount();

            System.Collections.Hashtable ht = new System.Collections.Hashtable();

            for (int nRow = 0; nRow < rowCnt; nRow++)
            //while (dr.Read())
            {
                if (flag)
                {
                    flag = false;
                    // create dbase file
                    hDbf = ShapeLib.DBFCreate(output);

                    ShapeLib.DBFAddField(hDbf, "HJGYCODE", ShapeLib.DBFFieldType.FTString, 10, 0);
                    ShapeLib.DBFAddField(hDbf, "JUSO", ShapeLib.DBFFieldType.FTString, 100, 0);
                    ShapeLib.DBFAddField(hDbf, "JIBEON", ShapeLib.DBFFieldType.FTString, 13, 0);
                    ShapeLib.DBFAddField(hDbf, "NSCODE", ShapeLib.DBFFieldType.FTString, 10, 0);
                    /*
                    if (!hDbf.Equals(IntPtr.Zero))
                    {
                        dt = dr.GetSchemaTable();
                        dt.Columns.Add("dBaseName");
                    }
                    int ordinal = 0;
                    foreach (DataRow row in dt.Rows)
                    {
                        string name = row["ColumnName"].ToString().ToUpper();
                        if (name.Length > 10)
                            name = name.Substring(0, 10);
                        int i = 0;
                        while (ht.ContainsKey(name))
                        {
                            string iVal = (i++).ToString();
                            if (name.Length + iVal.Length > 10)
                                name = name.Substring(0, 10 - iVal.Length) + iVal;
                            else
                                name = name + iVal;
                        }
                        ht.Add(name, ordinal++);
                        row["dBaseName"] = name;
                        string type = row["DataType"].ToString();
                        switch (type)
                        {
                            case "System.Int32":
                            case "System.Int16":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTInteger, 16, 0);
                                break;
                            case "System.String":
                                int len = Math.Min(255, int.Parse(row["ColumnSize"].ToString()));
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTString, len, 0);
                                break;
                            case "System.Boolean":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTLogical, 5, 0);
                                break;
                            case "System.Double":
                            case "System.Float":
                                int prec = int.Parse(row["NumericPrecision"].ToString());
                                int scale = int.Parse(row["NumericScale"].ToString());
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTDouble, prec, scale);
                                break;
                            case "System.DateTime":
                                ShapeLib.DBFAddField(hDbf, name, ShapeLib.DBFFieldType.FTInteger, 8, 0);
                                break;
                            default:
                                ht.Remove(name);
                                row["dBaseName"] = null;
                                ordinal--;
                                break;
                        }
                    }
                    */
                }

                //if (dr[xField] is DBNull || dr[yField] is DBNull)
                //    continue;

                //MessageBox.Show("#");
                //xCoord[0] = Double.Parse(dr[xField].ToString());
                //yCoord[0] = Double.Parse(dr[yField].ToString());

                xCoord[0] = Double.Parse(myQuery.getValueAt(nRow, xField).ToString());
                yCoord[0] = Double.Parse(myQuery.getValueAt(nRow, yField).ToString());

                IntPtr pShp = ShapeLib.SHPCreateObject(shpType, -1, 0, null, null, 1, xCoord, yCoord, null, null);
                ShapeLib.SHPWriteObject(hShp, -1, pShp);
                ShapeLib.SHPDestroyObject(pShp);

                ShapeLib.DBFWriteStringAttribute(hDbf, iShape, 0, myQuery.getValueAt(nRow, 0).ToString());
                ShapeLib.DBFWriteStringAttribute(hDbf, iShape, 1, myQuery.getValueAt(nRow, 1).ToString());
                ShapeLib.DBFWriteStringAttribute(hDbf, iShape, 2, myQuery.getValueAt(nRow, 2).ToString());
                ShapeLib.DBFWriteStringAttribute(hDbf, iShape, 3, myQuery.getValueAt(nRow, 3).ToString());

                /*foreach (DataRow row in dt.Rows)
                {
                    if (row["dBaseName"] == null)
                        continue;

                    int ordinal = (int)ht[row["dBaseName"].ToString()];
                    string fieldName = row["ColumnName"].ToString();
                    if (dr[fieldName] is DBNull)
                        continue;

                    switch (row["DataType"].ToString())
                    {
                        case "System.Int32":
                        case "System.Int16":
                            ShapeLib.DBFWriteIntegerAttribute(hDbf, iShape, ordinal, int.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.String":
                            ShapeLib.DBFWriteStringAttribute(hDbf, iShape, ordinal, dr[fieldName].ToString());
                            break;
                        case "System.Boolean":
                            ShapeLib.DBFWriteLogicalAttribute(hDbf, iShape, ordinal, bool.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.Double":
                        case "System.Float":
                            ShapeLib.DBFWriteDoubleAttribute(hDbf, iShape, ordinal, double.Parse(dr[fieldName].ToString()));
                            break;
                        case "System.DateTime":
                            DateTime date = DateTime.Parse(dr[fieldName].ToString());
                            ShapeLib.DBFWriteDateAttribute(hDbf, iShape, ordinal, date);
                            break;
                    }
                }*/
                iShape++;
            }
            // free resources
            ShapeLib.SHPClose(hShp);
            ShapeLib.DBFClose(hDbf);
        }

        private void Log(string messages)
        {
            txtMessages.Text += messages + "\r\n";
            txtMessages.Update();
            ScrollToBottom();
        }

        private void ScrollToBottom()
        {
            SendMessage((IntPtr)txtMessages.Handle, WM_VSCROLL, (IntPtr)SB_BOTTOM, (IntPtr)IntPtr.Zero);
        }
    }
}
